/*
 * Copyright (c) 2009. Silenus Consultoria, S.L.
 */
package es.silenus.detecta.controller;

import es.silenus.detecta.Constants;

import es.silenus.detecta.dao.Page;

import es.silenus.detecta.model.Role;
import es.silenus.detecta.model.User;
import es.silenus.detecta.model.User;

import es.silenus.detecta.service.OrganizationService;
import es.silenus.detecta.service.OrganizationService;
import es.silenus.detecta.service.UserService;
import es.silenus.detecta.service.UserService;

import es.silenus.detecta.util.FreemarkerHelper;
import es.silenus.detecta.util.MailHelper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.security.userdetails.UsernameNotFoundException;

import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.io.IOException;

import java.sql.Timestamp;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


/**
 * User controller.
 *
 * @author <a href="mailto:malonso@silenus-consultoria.es">Mariano Alonso</a>
 *
 * @since 01-abr-2009 20:20:59
 */
public class UserController extends BaseController {
	/**
	 * Logger for this class.
	 */
	private static final Log LOG = LogFactory.getLog(UserController.class);

	/**
	 * User details manager.
	 */
	private UserService userService;

	/**
	 * The organization manager.
	 */
	private OrganizationService organizationService;

	/**
	 * The remember template.
	 */
	private String mailTemplate;

	/**
	 * The remember subject key.
	 */
	private String mailSubjectKey;

	/**
	 * The alternate text key.
	 */
	private String alternateKey;

	/**
	 * The encoding.
	 */
	private String encoding;

	/**
	 * The base URL.
	 */
	private String baseURL;

	/**
	 * The mail helper.
	 */
	private MailHelper mailHelper;

	/**
	 * The freemarker helper.
	 */
	private FreemarkerHelper freemarkerHelper;

	/**
	 * Sets the user details manager.
	 *
	 * @param userService the user details manager.
	 */
	public void setUserService(final UserService userService) {
		this.userService = userService;
	}

	/**
	 * Sets the organization service.
	 *
	 * @param organizationService the organization service.
	 */
	public void setOrganizationService(final OrganizationService organizationService) {
		this.organizationService = organizationService;
	}

	/**
	 * Sets the remember template.
	 *
	 * @param mailTemplate the remember template.
	 */
	public void setMailTemplate(final String mailTemplate) {
		this.mailTemplate = mailTemplate;
	}

	/**
	 * Sets the remember subject key.
	 *
	 * @param mailSubjectKey the remember subject key.
	 */
	public void setMailSubjectKey(final String mailSubjectKey) {
		this.mailSubjectKey = mailSubjectKey;
	}

	/**
	 * Sets the alternate key.
	 *
	 * @param alternateKey the alternate key.
	 */
	public void setAlternateKey(final String alternateKey) {
		this.alternateKey = alternateKey;
	}

	/**
	 * Sets the encoding.
	 *
	 * @param encoding the encoding.
	 */
	public void setEncoding(final String encoding) {
		this.encoding = encoding;
	}

	/**
	 * Sets the base URL.
	 *
	 * @param baseURL the base URL.
	 */
	public void setBaseURL(final String baseURL) {
		this.baseURL = baseURL;
	}

	/**
	 * Sets the mail helper.
	 *
	 * @param mailHelper the mail helper.
	 */
	public void setMailHelper(final MailHelper mailHelper) {
		this.mailHelper = mailHelper;
	}

	/**
	 * Sets the freemarker helper.
	 *
	 * @param freemarkerHelper the freemarker helper.
	 */
	public void setFreemarkerHelper(final FreemarkerHelper freemarkerHelper) {
		this.freemarkerHelper = freemarkerHelper;
	}

	/**
	 * Updates the user.
	 *
	 * @param request the request.
	 * @param response the response.
	 *
	 * @return the view name.
	 */
	public String updateUser(final HttpServletRequest request, final HttpServletResponse response) {
		final User current = getUser(request);

		String id = request.getParameter("id");

		int userId = (id != null) ? Integer.parseInt(id) : 0;

		User user;
		String password = request.getParameter("password");

		if(userId > 0) {
			user = userService.findUserById(userId);
		} else {
			user = new User();
		}

		String temp = request.getParameter("login");

		// Only admins can change the user login
		if((temp != null) && current.isAdmin()) {
			user.setLogin(temp);

			User otherUser = null;

			try {
				otherUser = userService.loadUserByUsername(temp);
			} catch(UsernameNotFoundException e) {
				// do nothing
			}

			if((otherUser != null) && (otherUser.getId() != userId)) {
				request.setAttribute(Constants.ERRORS, "user.login.duplicated");

				return "secure/user-update-error";
			}
		}

		user.setFullname(request.getParameter("fullname"));
		user.setLanguage(request.getParameter("language"));
		user.setEmail(request.getParameter("email"));

		temp = request.getParameter("organization");

		if(temp != null) {
			// Only a global administrator can change the user organization
			if(current.isGlobalAdministrator()) {
				user.setOrganization(organizationService.findOrganizationById(Integer.parseInt(temp)));
			} else if(current.isOrganizationAdministrator()) {
				user.setOrganization(current.getOrganization());
			}
		} else if(current.isOrganizationAdministrator()) {
			// Users created by an organization administrator inherit their organization
			user.setOrganization(current.getOrganization());
		}

		temp = request.getParameter("role");

		// Only administrators can change the user role
		if((temp != null) && current.isAdmin()) {
			user.setRole(Role.getById(Integer.parseInt(temp)));
		}

		temp = request.getParameter("disableDate");

		// Only administrators can enable or disable users
		if((temp != null) && current.isAdmin()) {
			boolean disable = Boolean.parseBoolean(temp);

			if(disable) {
				user.setDisableDate(new Timestamp(System.currentTimeMillis()));
			} else {
				user.setDisableDate(null);
			}
		}

		if(userId > 0) {
			userService.updateUser(user);

			if(userId == current.getId()) {
				HttpSession session = request.getSession(false);

				session.setAttribute(Constants.USER, user);
				session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, user.getLocale());
			}

			if(password != null) {
				userService.changePassword(user.getName(), "", password);
				sendEmail(user, password);
			}
		} else {
			user.setPassword(password);
			userService.createUser(user);
			sendEmail(user, password);
		}

		request.setAttribute("updated_user", user);

		return "secure/user-updated";
	}

	/**
	 * Changes the user password.
	 *
	 * @param request the request.
	 * @param response the response.
	 *
	 * @return the view.
	 */
	public String changePassword(final HttpServletRequest request, final HttpServletResponse response) {
		String id = request.getParameter("id");
		int userId = (id != null) ? Integer.parseInt(id) : 0;

		User user = userService.findUserById(userId);

		String password = request.getParameter("password");

		userService.changePassword(user.getName(), "", password);

		sendEmail(user, password);


		return "secure/changed-password";
	}

	/**
	 * Finds users.
	 *
	 * @param request the request.
	 * @param response the response.
	 *
	 * @return the view.
	 */
	public String findUsers(final HttpServletRequest request, final HttpServletResponse response) {
		final User current = getUser(request);

		Map<String, Object> sample = new HashMap<String, Object>();
		String temp = request.getParameter("id");

		if(temp != null) {
			sample.put("id", temp);
		}

		temp = request.getParameter("login");

		if(temp != null) {
			sample.put("login", temp);
		}

		temp = request.getParameter("fullname");

		if(temp != null) {
			sample.put("fullname", temp);
		}

		temp = request.getParameter("email");

		if(temp != null) {
			sample.put("email", temp);
		}

		temp = request.getParameter("language");

		if(temp != null) {
			sample.put("language", temp);
		}

		temp = request.getParameter("role");

		if(temp != null) {
			Role role = Role.getById(Integer.parseInt(temp));

			sample.put("role", role);
		}

		// Only global administrators can reach any user
		if(current.isGlobalAdministrator()) {
			temp = request.getParameter("organization");

			if(temp != null) {
				sample.put("organization.id", Integer.parseInt(temp));
			}
		} else {
			sample.put("organization.id", current.getOrganization().getId());
		}

		temp = request.getParameter("disabled");

		if(temp != null) {
			sample.put("disabled", temp);
		}

		int start = Integer.parseInt(request.getParameter("start"));
		int limit = Integer.parseInt(request.getParameter("limit"));
		String[] sortFields = request.getParameterValues("sort");
		String[] sortDirections = request.getParameterValues("dir");

		Page<User> page = userService.findByExample(sample, start, limit, sortFields, sortDirections);

		request.setAttribute("page", page);

		return "secure/admin/users";
	}

	/**
	 * Sends an email.
	 *
	 * @param user the user.
	 * @param password the password.
	 *
	 * @return true if success, false otherwise.
	 */
	private boolean sendEmail(final User user, final String password) {
		Map<String, Object> model = new HashMap<String, Object>();

		model.put("user", user);
		model.put("password", password);
		model.put("baseURL", baseURL);

		try {
			String message = freemarkerHelper.process(mailTemplate, user.getLocale(), encoding, model);

			mailHelper.sendHTML(user.getEmail(), user.getFullname(), user.getLocale(), mailSubjectKey, alternateKey, message);

			return true;
		} catch(Exception e) {
			LOG.error("Error sending mail to user: " + user, e);

			return false;
		}
	}

	/**
	 * Redirects the client browser to the appropiate URL of his company folder in Alfresco.
	 *
	 * @param request the request.
	 * @param response the response.
	 *
	 * @return the view name or null.
	 *
	 * @throws IOException if something goes wrong.
	 */
	public String gotoAlfresco(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
		final User current = getUser(request);
		final String organizationName = current.getOrganization().getName();

		String alfrescoURL = organizationService.getAlfrescoURL(organizationName);

		alfrescoURL = response.encodeRedirectURL(alfrescoURL);
		response.sendRedirect(alfrescoURL);

		return null;
	}
}
